package com.ls.datalog.aspect;

import java.util.Date;
import java.util.List;

import org.apache.commons.beanutils.PropertyUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSON;
import com.ls.datalog.dao.ActionDao;
import com.ls.datalog.domain.Action;
import com.ls.datalog.domain.ActionType;
import com.ls.datalog.domain.ChangeItem;
import com.ls.datalog.utils.DiffUtils;

@Aspect
@Component
public class DataLogAspect {
	private Logger logger = LoggerFactory.getLogger(this.getClass());
	
	@Autowired
	private ActionDao actionDao;
	
	@Pointcut("execution(public * com..ProductDao.save*(..))")
	public void save() {}
	
	@Pointcut("execution(public * com..ProductDao.delete*(..))")
	public void delete() {}
	
	/**
	 * 对新增，更新，删除分别记录日志
	 * 新增和更新需要对比id
	 * 更新需要对比更新前后的字段差异，所以要在执行前后获取对象进行比对
	 * 新增需要在新增后记录id
	 * 删除直接获取对象，在执行成功后记录
	 * 
	 * 难点是如何获取对象差异,通过反射逐个字段比较
	 * @param joinPoint
	 * @throws Throwable 
	 */
	@Around("save()||delete()")
	public void recordDataLog(ProceedingJoinPoint joinPoint) throws Throwable {
		logger.debug("before record Data log");
		Object obj = joinPoint.getArgs()[0];
		String methodName = joinPoint.getSignature().getName();
		ActionType type;
		Action action = new Action();
		List<ChangeItem> items=null;
		Long id=null;
		if(methodName.equals("save")) {
			try{
                id = Long.valueOf(PropertyUtils.getProperty(obj,"id").toString());
            }catch (Exception e){
                //ignore
            }
			if(null==id) {//insert
				type=ActionType.INSERT;
				items = DiffUtils.getInsertChangeItems(obj);
			}else {//update 更新前后对比对象
				type=ActionType.UPDATE;
				action.setObjectId(id+"");
				items = DiffUtils.getUpdateChangeItems(DiffUtils.findById(joinPoint.getTarget(),Long.valueOf(PropertyUtils.getProperty(obj,"id").toString())),obj);
			}
		}else {//delete ,使用对象删除，或者id删除
			type=ActionType.DELETE;
			if(obj instanceof Long) {
				obj = DiffUtils.findById(joinPoint.getTarget(),Long.valueOf(String.valueOf(obj)));
			}
			items = DiffUtils.getDeleteChangeItems(obj);
			action.setObjectId(String.valueOf(PropertyUtils.getProperty(obj, "id")));
		}
		
		Object ret = joinPoint.proceed(joinPoint.getArgs());//真正调用
		
		if(type==ActionType.INSERT) {
			action.setObjectId(String.valueOf(PropertyUtils.getProperty(ret, "id")));
		}
		
		action.setItems(items);
		action.setType(type);
		action.setOperateTime(DiffUtils.getFieldStringValue(Date.class, new Date()));
		action.setOperator("admin");//ThreadLocal
		action.setObjectClass(obj.getClass().getName());
		 actionDao.save(action);
		 logger.info("save action {} finished ",JSON.toJSONString(action));
	}
}
